package com.our.base.easylog.es;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.our.base.easylog.EasyLogFactory;
import com.our.base.easylog.IPushLog;
import com.our.base.easylog.config.cache.CachePool;
import com.our.base.easylog.config.es.EsProperties;
import com.our.base.easylog.entity.EasyLogInfo;
import com.our.base.easylog.entity.LogInfo;
import com.our.base.easylog.es.document.LogDocument;
import com.our.base.easylog.es.service.BaseService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * es日志推送实现
 *
 * @author Alice
 * @date 2023/11/29
 **/
@Slf4j(topic = "easy-log")
public class EsPushLogImpl implements IPushLog {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private BaseService baseService;

    private final EsProperties esProperties;
    private CachePool cachePool = CachePool.getCachePool();
    private EasyLogInfo easyLogInfo= EasyLogFactory.getEasyLogInfo();

    public EsPushLogImpl(EsProperties esProperties) {
        this.esProperties = esProperties;
    }

    @Override
    public void pushLog() {
        //拿缓存池里面的数据
        List<Object> logInfoList = cachePool.getAll();
        log.info("推送日志{}条" ,logInfoList.size());
        if (logInfoList.isEmpty()) {
            return;
        }
        HashMap<String, Object> field = new HashMap<>();
        // TODO 根据字段类型映射es类型
        for (Field declaredField : LogDocument.class.getDeclaredFields()) {

            Map<String, String> type = new HashMap<>();
            if ("mdc".equals(declaredField.getName())) {
                type.put("type", "object"); // 或者 "nested"
            } else {
                type.put("type", "text");
            }
            field.put(declaredField.getName(), type);
        }
        //应用名称当作es索引名
        boolean checkIndex = baseService.checkIndex(easyLogInfo.getApplicationName());
        if (!checkIndex){
            baseService.createIndex(easyLogInfo.getApplicationName(), field);
        }

        logInfoList.forEach(obj ->
                asyncWrite(easyLogInfo.getApplicationName(), new LogDocument(((LogInfo) obj).getLog(),
                        ((LogInfo) obj).getLogTime(),((LogInfo) obj).getMdcInfo()))

        );
    }


    private void asyncWrite(String indexName, LogDocument logDocument) {
        IndexRequest indexRequest = new IndexRequest(indexName);
        indexRequest.source(JSON.toJSONString(logDocument), XContentType.JSON);
        String s = JSON.toJSONString(logDocument);
        indexRequest.source(s, XContentType.JSON);
        indexRequest.timeout(TimeValue.timeValueSeconds(1));
        indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
        //数据为存储而不是更新
        indexRequest.create(false);
        indexRequest.id(UUID.fastUUID().toString());
        restHighLevelClient.indexAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
            @Override
            public void onResponse(IndexResponse indexResponse) {
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        log.error("将id为：{}的数据存入ES时存在失败的分片，原因为：{}", indexRequest.id(), failure.getCause());
                    }
                }
            }

            @Override
            public void onFailure(Exception e) {
                log.error("{}:存储es时异常，数据信息为", indexRequest.id(), e);
            }
        });
    }
}
